package org.ejde.sciencelogs;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import javax.swing.border.TitledBorder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.ejde.layout.SpringUtilities;
import org.jivesoftware.smack.XMPPException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * This class contains the attributes and behaviors for the
 * Eventlog subpanels.
 *  
 * @author Eric Martin
 * @version 0.1
 */
public class subPanel extends JPanel implements ActionListener {
	
	/**
	 * Configuration information
	 */
	public iniParser ini;
	
	/**
	 * formField database
	 */
	public fieldFactory factory;
	
	/**
	 * UDP-based logging client
	 */
	public UdpXmitter udp;
	
	/**
	 * XMPP-based logging client
	 */
	public smackClient smack;

	/**
	 * Parent Panel ID
	 */
	public int pid;
	
	/**
	 * ID for this subpanel
	 */
	public int spid;
	
	/**
	 * Text of last message sent
	 */
	public String lastmessage = "No Last Message";

	/**
	 * JPanel containing the formfield JComponets
	 */
	public JPanel fieldtable;
	
	/**
	 * JPanel that contains the submit and View last
	 * JButtons
	 */
	public JPanel bot;
	
	/**
	 * JPanel that contains the expand/collapse button
	 */
	public JPanel west;
	
	/**
	 * JButton that expands/collapses the contents of the
	 * subpanel
	 */
	public JButton showfields;

	/**
	 * Boolean flag controlling the default behavior of the
	 * subpanel
	 */
	public boolean shrinkonopen = true;

	/**
	 * Constructor method
	 * 
	 * @param ini configuration information
	 * @param factory formfield database
	 * @param udp UDP-based logging client
	 * @param smack XMPP-based logging client
	 * @param panelID ID for the parent JPanel
	 * @param subpanelID ID for the current subpanel
	 */
	public subPanel(iniParser ini, fieldFactory factory, UdpXmitter udp,
			smackClient smack, int panelID, int subpanelID) {
		
		//Copy arguments to current object
		this.ini = ini;
		this.factory = factory;
		this.udp = udp;
		this.smack = smack;
		this.pid = panelID;
		this.spid = subpanelID;

		//Extract the formfield objects for the current subpanel
		formField[] spf = factory.getSubpanelFields(panelID, subpanelID);

		// Initialize the Panel
		this.fieldtable = new JPanel();

		// Set the panel layout manager
		this.fieldtable.setLayout(new SpringLayout());

		// Initialize the title and border for the subpanel
		TitledBorder title;
		title = BorderFactory.createTitledBorder(ini.getSubpanelAttribute(
				panelID, subpanelID, "name"));
		this.setBorder(title);
		this.setLayout(new BorderLayout());

		// Add the JComponents in the fieldform database to the subpanel
		for (int n = 0; n < spf.length; n++) {
			this.fieldtable.add(spf[n].getLabel());
			// Get the appropriate action
			switch (spf[n].type) {
			case formField.TEXT_FIELD:
				this.fieldtable.add(spf[n].getTextField());
				break;
			case formField.LIST_FIELD:
				this.fieldtable.add(spf[n].getListField());
				break;
			case formField.TEXTAREA_FIELD:
				this.fieldtable.add(spf[n].getTextAreaField());
				break;
			}
		}

		// Pack the JPanel
		SpringUtilities.makeCompactGrid(this.fieldtable, spf.length, 2, 30, 3,
				3, 3);

		// Create West Panel
		this.west = new JPanel(new FlowLayout());

		// Initialize the collase button
		this.showfields = new JButton("-");
		showfields.addActionListener(this);
		this.west.add(showfields);

		// Create Bottom Panel
		this.bot = new JPanel();
		this.bot.setLayout(new FlowLayout(FlowLayout.TRAILING));

		JButton viewlast = new JButton("View Last");
		viewlast.addActionListener(this);
		this.bot.add(viewlast);

		JButton submit = new JButton("Submit");
		submit.addActionListener(this);
		this.bot.add(submit);

		// Add the JPanels to the subpanel JPanel
		this.add("Center", this.fieldtable);
		this.add("South", this.bot);
		this.add("West", this.west);

		// Depending on the default behavior, collapse the
		// subpanel.
		String shrinkOnOpen = this.ini.getSubpanelAttribute(panelID,
				subpanelID, "shrinkonopen");
		if (shrinkOnOpen != null) {
			if (shrinkOnOpen.equals("1")) {
				shrinkonopen = true;
			} else {
				shrinkonopen = false;
			}
		}

	}

	/**
	 * Call the dialog window containing the last message. 
	 */
	public void viewLast() {
		// prep last message

		String dlm = ini.getLoggerDelimiter();

		JOptionPane.showMessageDialog(factory.frame,
				this.lastmessage.replace(dlm, "\n"));

	}

	/**
	 * Submit the message to the logging server.
	 */
	public void submit() {
		// System.out.println("BUTTON HIT! PID: "+this.pid+" SPID: "+this.spid);

		String txtout = "";
		String xmlout = "";
		String dlm = ini.getLoggerDelimiter();

		// try xml output
		try {
			xmlout = this.submitXML();

		} catch (ParserConfigurationException e1) {
			e1.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}

		// try text output
		txtout = this.submitText();

		// UDP Output
		try {
			udp.send(txtout);
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.lastmessage = txtout;

		// Output TEXT
		// Smack XMPP Output (we must be logged in to get anywhere near here.
		if (ini.getXmppEnabled() == 1) {
			try {
				smack.sendMessage("LOG" + dlm + txtout);
				smack.increaseEventCount();
			} catch (XMPPException e) {
				e.printStackTrace();
			}
		}

		// OutputXML
		// Smack XMPP Output (we must be logged in to get anywhere near here.
		if (ini.getXmppEnabled() == 1) {
			try {
				smack.sendMessage(xmlout);
			} catch (XMPPException e) {
				e.printStackTrace();
			}
		}

		System.out.println(txtout);
		System.out.println(xmlout);

		// clear fields automatically after submission is complete
		this.submitCheckandClear();

	}

	/**
	 * Build the plain text version of the event output.
	 * 
	 * @return String object containing the output text.
	 */
	public String submitText() {// System.out.println("BUTTON HIT! PID: "+this.pid+" SPID: "+this.spid);

		String out = "";
		String dlm = ini.getLoggerDelimiter();

		// Get Logger Instance
		out = out + ini.getLoggerCategory().toUpperCase() + dlm;

		// Get Panel and Subpanel Name
		out = out + ini.getPanelAttribute(pid, "category").toUpperCase() + dlm;
		out = out
				+ ini.getSubpanelAttribute(pid, spid, "category").toUpperCase()
				+ dlm;

		// Assemble toppanel fields
		formField[] tpf = factory.getTopPanelFields();
		if (tpf.length != 0) {
			for (int n = 0; n < tpf.length; n++) {
				if (tpf[n].type != formField.TEXTAREA_FIELD) {
					out = out + tpf[n].getValue() + dlm;
				}
			}
		}

		// Assemble panel fields
		formField[] pf = factory.getPanelFields(pid);
		if (pf.length != 0) {
			for (int n = 0; n < pf.length; n++) {
				if (pf[n].type != formField.TEXTAREA_FIELD) {
					out = out + pf[n].getValue() + dlm;
				}
			}
		}

		// Assemble subpanel fields
		formField[] spf = factory.getSubpanelFields(pid, spid);
		for (int n = 0; n < spf.length; n++) {
			if (spf[n].type != formField.TEXTAREA_FIELD) {
				out = out + spf[n].getValue() + dlm;
			}
		}

		if (tpf.length != 0) {
			for (int n = 0; n < tpf.length; n++) {
				if (tpf[n].type == formField.TEXTAREA_FIELD) {
					out = out + tpf[n].getValue() + dlm;
				}
			}
		}

		return out;

	}

	/**
	 * Build the XML version of the event output.
	 * 
	 * @return String object containing the output XML
	 * text.
	 * 
	 * @throws ParserConfigurationException
	 * @throws TransformerException
	 */
	public String submitXML() throws ParserConfigurationException,
			TransformerException {

		// Build an XML document
		DocumentBuilderFactory domfactory = DocumentBuilderFactory
				.newInstance();
		DocumentBuilder builder = domfactory.newDocumentBuilder();
		DOMImplementation impl = builder.getDOMImplementation();
		Document doc = impl.createDocument(null, null, null);

		Element entry = doc.createElement("entry");
		entry.setAttribute("type", ini.getLoggerCategory().toLowerCase());

		// Get Panel and Subpanel Name
		entry.setAttribute("category", ini.getPanelAttribute(pid, "category"));
		entry.setAttribute("subcategory",
				ini.getSubpanelAttribute(pid, spid, "category"));

		// Assemble toppanel fields
		formField[] tpf = factory.getTopPanelFields();
		if (tpf.length != 0) {
			for (int n = 0; n < tpf.length; n++) {
				if (tpf[n].type != formField.TEXTAREA_FIELD) {
					Element elms = tpf[n].toElement(doc);
					entry.appendChild(elms);
				}
			}
		}

		// Assemble panel fields
		formField[] pf = factory.getPanelFields(pid);
		if (pf.length != 0) {
			for (int n = 0; n < pf.length; n++) {
				if (pf[n].type != formField.TEXTAREA_FIELD) {
					Element elms = pf[n].toElement(doc);
					entry.appendChild(elms);
				}
			}
		}

		// Assemble subpanel fields
		formField[] spf = factory.getSubpanelFields(pid, spid);
		for (int n = 0; n < spf.length; n++) {
			if (spf[n].type != formField.TEXTAREA_FIELD) {
				Element elms = spf[n].toElement(doc);
				entry.appendChild(elms);
			}
		}

		if (tpf.length != 0) {
			for (int n = 0; n < tpf.length; n++) {
				if (tpf[n].type == formField.TEXTAREA_FIELD) {
					Element elms = tpf[n].toElement(doc);
					entry.appendChild(elms);
				}
			}
		}

		doc.appendChild(entry);

		// output xml to console
		// transform the Document into a String
		DOMSource domSource = new DOMSource(doc);
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer transformer = tf.newTransformer();
		transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
		transformer.setOutputProperty(OutputKeys.METHOD, "xml");
		transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
		transformer.setOutputProperty(
				"{http://xml.apache.org/xslt}indent-amount", "4");
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		java.io.StringWriter sw = new java.io.StringWriter();
		StreamResult sr = new StreamResult(sw);
		transformer.transform(domSource, sr);
		String xml = sw.toString();

		return xml;

	}

	/**
	 * Clear the fields after event submission.  The
	 * checkAndClear() method return determines if the
	 * field is actually cleared after submission.
	 */
	public void submitCheckandClear() {
		
		// Assemble toppanel fields
		formField[] tpf = factory.getTopPanelFields();
		if (tpf.length != 0) {
			for (int n = 0; n < tpf.length; n++) {
				if (tpf[n].type != formField.TEXTAREA_FIELD) {
					tpf[n].checkAndClear();
				}
			}
		}

		// Assemble panel fields
		formField[] pf = factory.getPanelFields(pid);
		if (pf.length != 0) {
			for (int n = 0; n < pf.length; n++) {
				if (pf[n].type != formField.TEXTAREA_FIELD) {
					pf[n].checkAndClear();
				}
			}
		}

		// Assemble subpanel fields
		formField[] spf = factory.getSubpanelFields(pid, spid);
		for (int n = 0; n < spf.length; n++) {
			if (spf[n].type != formField.TEXTAREA_FIELD) {
				spf[n].checkAndClear();
			}
		}

		if (tpf.length != 0) {
			for (int n = 0; n < tpf.length; n++) {
				if (tpf[n].type == formField.TEXTAREA_FIELD) {
					tpf[n].checkAndClear();
				}
			}
		}
	}

	/**
	 * Hide the subpanel
	 */
	public void shrink() {
		this.fieldtable.setVisible(false);
		this.bot.setVisible(false);

		// factory.frame.setVisible(false);
		factory.frame.pack();
		factory.frame.repaint();
		// factory.frame.setVisible(true);

	}

	/**
	 * Expand the subpanel
	 */
	public void expand() {
		this.fieldtable.setVisible(true);
		this.bot.setVisible(true);
		// factory.frame.setVisible(false);
		factory.frame.pack();
		factory.frame.repaint();
		// factory.frame.update();
		// factory.frame.setVisible(true);

	}

	/**
	 * Method hides/shows the subpanel on startup based on
	 * the shrinkonopen flag.
	 */
	public void shrinkInit() {
		if (this.shrinkonopen) {
			this.shrink();
			this.showfields.setText("+");
		}
	}

	public void actionPerformed(ActionEvent evt) {
		if (evt.getActionCommand().equals("Submit")) {
			this.submit();
		} else if (evt.getActionCommand().equals("View Last")) {
			this.viewLast();
		} else if (evt.getActionCommand().equals("-")) {
			this.shrink();
			this.showfields.setText("+");
		} else if (evt.getActionCommand().equals("+")) {
			this.expand();
			this.showfields.setText("-");
		}

	}
}